package com.fenyin.samples.study.jdk.nio.channels.file;

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Random;

/**
 * 使用独占锁写文件
 *@Author:fengzhichao  
 *@Since:2012-12-14  
 *@Version:1.1.0
 */
public class FileExclusiveWriter {
	
	private static final int SIZEOF_INT = 4;
	private static final int INDEX_START = 0;
	private static final int INDEX_COUNT = 10;
	private static final int INDEX_SIZE = INDEX_COUNT * SIZEOF_INT;
	
	private ByteBuffer buffer = ByteBuffer.allocate(INDEX_SIZE);
	
	private IntBuffer indexBuffer = buffer.asIntBuffer();
	
	private Random rand = new Random();
	
	private static final String filename="temp.txt";
	
	// Write new values to the index slots
	private int idxval = 1;
	
	private int lastLineLen = 0;

	public static void main(String[] argv) throws Exception{
		
		RandomAccessFile file = new RandomAccessFile(filename, "rw");
		FileChannel fileChannel = file.getChannel();
		FileExclusiveWriter writer = new FileExclusiveWriter();
		writer.doUpdates(fileChannel);
	}

	// Simulate a series of updates to the index area
	// while holding an exclusive lock
	void doUpdates(FileChannel fileChannel) throws Exception {
		while (true) {
			println("trying for exclusive lock...");
			FileLock lock = fileChannel.lock(INDEX_START, INDEX_SIZE, false);
			try{
				//执行IO操作
				updateIndex(fileChannel);
			}catch(Throwable th){
				th.printStackTrace();
			}finally{
				lock.release();
				println("<sleeping>");
				Thread.sleep(rand.nextInt(2000) + 500);
			}
			
		}
	}

	private void updateIndex(FileChannel fileChannel) throws Exception {
		// "indexBuffer" is an int view of "buffer"
		indexBuffer.clear();
		for (int i = 0; i < INDEX_COUNT; i++) {
			idxval++;
			println("Updating index " + i + "=" + idxval);
			indexBuffer.put(idxval);
			// Pretend that this is really hard work
			Thread.sleep(500);
		}
		// leaves position and limit correct for whole buffer
		buffer.clear();
		fileChannel.write(buffer, INDEX_START);

	}

	// ----------------------------------------------------------------
	// Specialized println that repaints the current line
	private void println(String msg) {
		System.out.print("\r ");
		System.out.print(msg);
		for (int i = msg.length(); i < lastLineLen; i++) {
			System.out.print(" ");
		}
		System.out.print("\r");
		System.out.flush();
		lastLineLen = msg.length();
	}
}